package com.itheima.d7_tcp4;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 *  目标：完成TCP通信快速入门-服务端开发：要求实现与多个客户端同时通信。
 *      案例，即时通信：群聊
 *
 *
 * 1、群聊是什么含义？ 怎么实现？
 * 是指一个客户端把消息发出去，其他在线的全部客户端都可以收到消息。
 * 需要用到端口转发的设计思想。
 * 服务端需要把在线的Socket管道存储起来，一旦收到一个消息要推送给其他管道
 *
 *  TCP通信-端口转发思想：
 *  之前的案例都是客户端->服务端，群聊是指客户端->多个客户端
 *  1.但是客户端和客户端实际是不能直接通信的，还是需要准备个服务端。那就意味着服务端还是要有一个主线程
 *      使用一个死循环来不断地接收客户端通信管道连接建立socket通信管道，接着分别分配子线程来处理这些socket通信管道。
 *      比如说客户端1通过socket管道发送了信息到服务端来了，由对应的子线程负责接收处理，
 *      然后子线程需要把该客户端发过来的信息分发给其他所有在线的socket通信管道
 *  2.问题又来了，怎么知道哪些管道是在线的，服务端又没有记录多少在线的socket管道
 *      所以服务端还需要提供一个集合：存储在线socket管道，并且只需要一个
 *
 *
 * 我：
 * 这个案例比较难理清楚的是，众多客户端，每一个都会和服务端建立socket管道。然后客户端除了发送消息给服务端，还要接收其他客户端的信息，
 * 我自己也没怎么理解
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建Socket对象，并同时请求与服务端程序的连接。
        Socket socket = new Socket("127.0.0.1", 8888);

 /*
     注意，此时启动的每一个客户端都在不断地往外面发消息。并且，唯一的服务端在收到每一个客户端的消息后都分配了单独的线程处理，
       然后每一个线程都会持续把收到的对应的客户端消息，分发给所有的在线的客户端和自己。
       所以客户端管道除了要对外建立socket管道发消息之外，还需要接收服务端转发的其他客户端的消息.
       现在客户端只有一个主线程，该线程是负责不断地对外发消息，那么谁能负责不断地接收消息。
       所以必须单独定义一个线程出来处理客户端接收的消息
  */

        // 创建一个独立的线程，负责随机从socket中接收服务端发送过来的消息。
        new ClientReaderThread(socket).start();

        // 2、从socket通信管道中得到一个字节输出流，用来发数据给服务端程序。
        OutputStream os = socket.getOutputStream();
        // 3、把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说：");
            String msg = sc.nextLine();

            // 一旦用户输入了exit，就退出客户端程序
            if("exit".equals(msg)){
                System.out.println("欢迎您下次光临！退出成功！");
                dos.close();
                socket.close();
                break;
            }
            // 4、开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}
